home *** CD-ROM | disk | FTP | other *** search
/ MacAddict 83 / MacAddict_083_2003-07.iso / mac / Software / Development / VLC Source 0.5.3.dmg / modules / control / gestures.c next >
C/C++ Source or Header  |  2003-03-30  |  13KB  |  380 lines

  1. /*****************************************************************************
  2.  * geatures.c: control vlc with mouse gestures
  3.  *****************************************************************************
  4.  * Copyright (C) 2002 VideoLAN
  5.  * $Id: gestures.c,v 1.4 2003/03/30 18:14:37 gbazin Exp $
  6.  *
  7.  * Authors: Sigmund Augdal <sigmunau@idi.ntnu.no>
  8.  *
  9.  * This program is free software; you can redistribute it and/or modify
  10.  * it under the terms of the GNU General Public License as published by
  11.  * the Free Software Foundation; either version 2 of the License, or
  12.  * (at your option) any later version.
  13.  * 
  14.  * This program is distributed in the hope that it will be useful,
  15.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  * GNU General Public License for more details.
  18.  *
  19.  * You should have received a copy of the GNU General Public License
  20.  * along with this program; if not, write to the Free Software
  21.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  22.  *****************************************************************************/
  23.  
  24. /*****************************************************************************
  25.  * Preamble
  26.  *****************************************************************************/
  27. #include <stdlib.h>                                      /* malloc(), free() */
  28. #include <string.h>
  29. #include <unistd.h>
  30.  
  31. #include <vlc/vlc.h>
  32. #include <vlc/intf.h>
  33. #include <vlc/vout.h>
  34.  
  35. #include "stream_control.h"
  36. #include "input_ext-intf.h"
  37.  
  38. /*****************************************************************************
  39.  * intf_sys_t: description and status of interface
  40.  *****************************************************************************/
  41. struct intf_sys_t
  42. {
  43.     vlc_object_t *      p_vout;
  44.     input_thread_t *    p_input;
  45.     vlc_bool_t          b_got_gesture;
  46.     vlc_bool_t          b_button_pressed;
  47.     int                 i_mouse_x, i_mouse_y;
  48.     int                 i_last_x, i_last_y;
  49.     unsigned int        i_pattern;
  50.     int                 i_num_gestures;
  51.     int                 i_threshold;
  52.     int                 i_button_mask;
  53. };
  54.  
  55. /*****************************************************************************
  56.  * Local prototypes.
  57.  *****************************************************************************/
  58. #define UP 1
  59. #define DOWN 2
  60. #define LEFT 3
  61. #define RIGHT 4
  62. #define NONE 0
  63. #define GESTURE( a, b, c, d ) (a | ( b << 4 ) | ( c << 8 ) | ( d << 12 ))
  64.  
  65. int  E_(Open)   ( vlc_object_t * );
  66. void E_(Close)  ( vlc_object_t * );
  67. static int  InitThread     ( intf_thread_t *p_intf );
  68. static int  MouseEvent     ( vlc_object_t *, char const *,
  69.                              vlc_value_t, vlc_value_t, void * );
  70.  
  71. /* Exported functions */
  72. static void RunIntf        ( intf_thread_t *p_intf );
  73.  
  74. /*****************************************************************************
  75.  * Module descriptor
  76.  *****************************************************************************/
  77. #define THRESHOLD_TEXT N_( "Motion threshold" )
  78. #define THRESHOLD_LONGTEXT N_( \
  79.     "the amount of movement required for a mouse" \
  80.     " gesture to be recorded" )
  81.  
  82. #define BUTTON_TEXT N_( "Mouse button" )
  83. #define BUTTON_LONGTEXT N_( \
  84.     "the mouse button to be held down during mouse gestures" )
  85.  
  86. static char *button_list[] = { "left", "middle", "right", NULL };
  87.  
  88. vlc_module_begin();
  89.     add_category_hint( N_( "Gestures" ), NULL, VLC_FALSE );
  90.     add_integer( "gestures-threshold", 30, NULL, THRESHOLD_TEXT, THRESHOLD_LONGTEXT, VLC_TRUE );
  91.     add_string_from_list( "gestures-button", "right", button_list, NULL,
  92.                           BUTTON_TEXT, BUTTON_LONGTEXT, VLC_FALSE );
  93.     set_description( _("mouse gestures control interface") );
  94.  
  95.     set_capability( "interface", 0 );
  96.     set_callbacks( E_(Open), E_(Close) );
  97. vlc_module_end();
  98.  
  99. /*****************************************************************************
  100.  * OpenIntf: initialize interface
  101.  *****************************************************************************/
  102. int E_(Open) ( vlc_object_t *p_this )
  103. {
  104.     intf_thread_t *p_intf = (intf_thread_t *)p_this;
  105.  
  106.     /* Allocate instance and initialize some members */
  107.     p_intf->p_sys = malloc( sizeof( intf_sys_t ) );
  108.     if( p_intf->p_sys == NULL )
  109.     {
  110.         return( 1 );
  111.     };
  112.  
  113.     p_intf->pf_run = RunIntf;
  114.  
  115.     return( 0 );
  116. }
  117.  
  118. /*****************************************************************************
  119.  * gesture: return a subpattern within a pattern
  120.  *****************************************************************************/
  121. static int gesture( int i_pattern, int i_num )
  122. {
  123.     return ( i_pattern >> ( i_num * 4 ) ) & 0xF;
  124. }
  125.         
  126. /*****************************************************************************
  127.  * CloseIntf: destroy dummy interface
  128.  *****************************************************************************/
  129. void E_(Close) ( vlc_object_t *p_this )
  130. {
  131.     intf_thread_t *p_intf = (intf_thread_t *)p_this;
  132.  
  133.     /* Destroy structure */
  134.     free( p_intf->p_sys );
  135. }
  136.  
  137.  
  138. /*****************************************************************************
  139.  * RunIntf: main loop
  140.  *****************************************************************************/
  141. static void RunIntf( intf_thread_t *p_intf )
  142. {
  143.     playlist_t * p_playlist = NULL;
  144.     p_intf->p_sys->p_vout = NULL;
  145.  
  146.     if( InitThread( p_intf ) < 0 )
  147.     {
  148.         msg_Err( p_intf, "can't initialize intf" );
  149.         return;
  150.     }
  151.     msg_Dbg( p_intf, "intf initialized" );
  152.  
  153.     /* Main loop */
  154.     while( !p_intf->b_die )
  155.     {
  156.         vlc_mutex_lock( &p_intf->change_lock );
  157.  
  158.         /* 
  159.          * mouse cursor
  160.          */
  161.         if( p_intf->p_sys->b_got_gesture )
  162.         {
  163.             /* Do something */
  164.             switch( p_intf->p_sys->i_pattern )
  165.             {
  166.             case LEFT:
  167.                 p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
  168.                                               FIND_ANYWHERE );
  169.                 if( p_playlist == NULL )
  170.                 {
  171.                     break;
  172.                 }
  173.                 
  174.                 playlist_Prev( p_playlist );
  175.                 vlc_object_release( p_playlist );
  176.                 break;
  177.             case RIGHT:
  178.                 p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
  179.                                               FIND_ANYWHERE );
  180.                 if( p_playlist == NULL )
  181.                 {
  182.                     break;
  183.                 }
  184.                 
  185.                 playlist_Next( p_playlist );
  186.                 vlc_object_release( p_playlist );
  187.                 break;
  188.             case GESTURE(UP,RIGHT,NONE,NONE):
  189.                 if (p_intf->p_sys->p_vout )
  190.                 {
  191.                     ((vout_thread_t *)p_intf->p_sys->p_vout)->i_changes |=
  192.                         VOUT_FULLSCREEN_CHANGE;
  193.                 }
  194.                 break;
  195.             case GESTURE(DOWN,RIGHT,NONE,NONE):
  196.                 p_intf->p_vlc->b_die = VLC_TRUE;
  197.                 msg_Dbg(p_intf, "Should close the vout!" );
  198.                 break;
  199.             case GESTURE(DOWN,LEFT,UP,RIGHT):
  200.                 msg_Dbg(p_intf, "A square!" );
  201.                 break;
  202.             default:
  203.                 break;
  204.             }
  205.             p_intf->p_sys->i_num_gestures = 0;
  206.             p_intf->p_sys->i_pattern = 0;
  207.             p_intf->p_sys->b_got_gesture = VLC_FALSE;
  208.         }
  209.                 
  210.  
  211.         vlc_mutex_unlock( &p_intf->change_lock );
  212.  
  213.         /* 
  214.          * video output
  215.          */
  216.         if( p_intf->p_sys->p_vout && p_intf->p_sys->p_vout->b_die )
  217.         {
  218.             var_DelCallback( p_intf->p_sys->p_vout, "mouse-moved",
  219.                              MouseEvent, p_intf );
  220.             var_DelCallback( p_intf->p_sys->p_vout, "mouse-button-down",
  221.                              MouseEvent, p_intf );
  222.             vlc_object_release( p_intf->p_sys->p_vout );
  223.             p_intf->p_sys->p_vout = NULL;
  224.         }
  225.  
  226.         if( p_intf->p_sys->p_vout == NULL )
  227.         {
  228.             p_intf->p_sys->p_vout = vlc_object_find( p_intf,
  229.                                       VLC_OBJECT_VOUT, FIND_ANYWHERE );
  230.             if( p_intf->p_sys->p_vout )
  231.             {
  232.                 var_AddCallback( p_intf->p_sys->p_vout, "mouse-moved",
  233.                                  MouseEvent, p_intf );
  234.                 var_AddCallback( p_intf->p_sys->p_vout, "mouse-button-down",
  235.                                  MouseEvent, p_intf );
  236.             }
  237.         }
  238.  
  239.         /* Wait a bit */
  240.         msleep( INTF_IDLE_SLEEP );
  241.     }
  242.  
  243.     if( p_intf->p_sys->p_vout )
  244.     {
  245.         var_DelCallback( p_intf->p_sys->p_vout, "mouse-moved",
  246.                          MouseEvent, p_intf );
  247.         var_DelCallback( p_intf->p_sys->p_vout, "mouse-button-down",
  248.                          MouseEvent, p_intf );
  249.         vlc_object_release( p_intf->p_sys->p_vout );
  250.     }
  251. }
  252.  
  253. /*****************************************************************************
  254.  * InitThread:
  255.  *****************************************************************************/
  256. static int InitThread( intf_thread_t * p_intf )
  257. {
  258.     char *psz_button;
  259.     /* we might need some locking here */
  260.     if( !p_intf->b_die )
  261.     {
  262.         input_thread_t * p_input;
  263.  
  264.         p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT, FIND_PARENT );
  265.  
  266.         vlc_mutex_lock( &p_intf->change_lock );
  267.  
  268.         p_intf->p_sys->p_input = p_input;
  269.         p_intf->p_sys->b_got_gesture = VLC_FALSE;
  270.         p_intf->p_sys->b_button_pressed = VLC_FALSE;
  271.         p_intf->p_sys->i_threshold = config_GetInt( p_intf, "gestures-threshold" );
  272.         psz_button = config_GetPsz( p_intf, "gestures-button" );
  273.         if ( !strcmp( psz_button, "left" ) )
  274.         {
  275.             p_intf->p_sys->i_button_mask = 1;
  276.         }
  277.         else if ( !strcmp( psz_button, "middle" ) )
  278.         {
  279.             p_intf->p_sys->i_button_mask = 2;
  280.         }
  281.         else if ( !strcmp( psz_button, "right" ) )
  282.         {
  283.             p_intf->p_sys->i_button_mask = 4;
  284.         }
  285.  
  286.         p_intf->p_sys->i_pattern = 0;
  287.         p_intf->p_sys->i_num_gestures = 0;
  288.         vlc_mutex_unlock( &p_intf->change_lock );
  289.  
  290.         return 0;
  291.     }
  292.     else
  293.     {
  294.         return -1;
  295.     }
  296. }
  297.  
  298. /*****************************************************************************
  299.  * MouseEvent: callback for mouse events
  300.  *****************************************************************************/
  301. static int MouseEvent( vlc_object_t *p_this, char const *psz_var,
  302.                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
  303. {
  304.     vlc_value_t val;
  305.     int pattern = 0;
  306.     
  307.     signed int i_horizontal, i_vertical;
  308.     intf_thread_t *p_intf = (intf_thread_t *)p_data;
  309.  
  310.     /* don't process new gestures before the last events are processed */
  311.     if( p_intf->p_sys->b_got_gesture ) {
  312.         return VLC_SUCCESS;
  313.     }
  314.  
  315.     vlc_mutex_lock( &p_intf->change_lock );
  316.     if( !strcmp(psz_var, "mouse-moved" ) && p_intf->p_sys->b_button_pressed ) {
  317.         var_Get( p_intf->p_sys->p_vout, "mouse-x", &val );
  318.         p_intf->p_sys->i_mouse_x = val.i_int;
  319.         var_Get( p_intf->p_sys->p_vout, "mouse-y", &val );
  320.         p_intf->p_sys->i_mouse_y = val.i_int;
  321.         i_horizontal = p_intf->p_sys->i_mouse_x -
  322.             p_intf->p_sys->i_last_x;
  323.         i_horizontal = i_horizontal / p_intf->p_sys->i_threshold;
  324.         i_vertical = p_intf->p_sys->i_mouse_y
  325.             - p_intf->p_sys->i_last_y;
  326.         i_vertical = i_vertical / p_intf->p_sys->i_threshold;
  327.         
  328.         if ( i_horizontal < 0 )
  329.         {
  330.             msg_Dbg( p_intf, "left gesture(%d)", i_horizontal );
  331.             pattern = LEFT;
  332.         }
  333.         else if ( i_horizontal > 0 )
  334.         {
  335.             msg_Dbg( p_intf, "right gesture(%d)", i_horizontal );
  336.             pattern = RIGHT;
  337.         }
  338.         if ( i_vertical < 0 )
  339.         {
  340.             msg_Dbg( p_intf, "up gesture(%d)", i_vertical );
  341.             pattern = UP;
  342.         }
  343.         else if ( i_vertical > 0 )
  344.         {
  345.             msg_Dbg( p_intf, "down gesture(%d)", i_vertical );
  346.             pattern = DOWN;
  347.         }
  348.         if (pattern )
  349.         {
  350.             p_intf->p_sys->i_last_y = p_intf->p_sys->i_mouse_y;
  351.             p_intf->p_sys->i_last_x = p_intf->p_sys->i_mouse_x;
  352.             if( gesture(p_intf->p_sys->i_pattern, p_intf->p_sys->i_num_gestures - 1 ) != pattern )
  353.             {
  354.                 p_intf->p_sys->i_pattern |= pattern << ( p_intf->p_sys->i_num_gestures * 4 );
  355.                 p_intf->p_sys->i_num_gestures++;
  356.             }
  357.         }
  358.  
  359.     }
  360.     if( !strcmp( psz_var, "mouse-button-down" ) && newval.i_int & p_intf->p_sys->i_button_mask
  361.         && !p_intf->p_sys->b_button_pressed )
  362.     {
  363.         p_intf->p_sys->b_button_pressed = VLC_TRUE;
  364.         var_Get( p_intf->p_sys->p_vout, "mouse-x", &val );
  365.         p_intf->p_sys->i_last_x = val.i_int;
  366.         var_Get( p_intf->p_sys->p_vout, "mouse-y", &val );
  367.         p_intf->p_sys->i_last_y = val.i_int;
  368.     }
  369.     if( !strcmp( psz_var, "mouse-button-down" ) && !( newval.i_int & p_intf->p_sys->i_button_mask )
  370.         && p_intf->p_sys->b_button_pressed )
  371.     {
  372.         p_intf->p_sys->b_button_pressed = VLC_FALSE;
  373.         p_intf->p_sys->b_got_gesture = VLC_TRUE;
  374.     }
  375.  
  376.     vlc_mutex_unlock( &p_intf->change_lock );
  377.  
  378.     return VLC_SUCCESS;
  379. }
  380.